package com.cloudbroker.bcs.csvc.lightinvesting.facade.service;

import com.cloudbroker.bcs.common.jres.util.JresUtil;
import com.cloudbroker.bcs.common.util.ReflectionUtil;
import com.cloudbroker.bcs.common.util.VOUtil;
import com.cloudbroker.bcs.common.util.ValueUtil;
import com.cloudbroker.bcs.csvc.lightinvesting.api.constants.LedFields;
import com.cloudbroker.bcs.csvc.lightinvesting.api.util.LedUtil;
import com.cloudbroker.bcs.csvc.lightinvesting.api.vo.request.base.IFSForm;
import com.hundsun.t2sdk.common.core.context.ContextUtil;
import com.hundsun.t2sdk.common.share.dataset.MapWriter;
import com.hundsun.t2sdk.common.util.ResourceUtils;
import com.hundsun.t2sdk.impl.client.T2Services;
import com.hundsun.t2sdk.interfaces.IClient;
import com.hundsun.t2sdk.interfaces.T2SDKException;
import com.hundsun.t2sdk.interfaces.share.dataset.IDatasets;
import com.hundsun.t2sdk.interfaces.share.event.EventReturnCode;
import com.hundsun.t2sdk.interfaces.share.event.EventType;
import com.hundsun.t2sdk.interfaces.share.event.IEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.annotation.PostConstruct;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by fangyf18371 on 2016/11/3.
 */
@Service
public class IFST2RemoteService {
    private static final Logger LOG = LoggerFactory.getLogger(IFST2RemoteService.class);
    private T2Services sdkServices = null;

    private static boolean isWindow = false;

    @PostConstruct
    public void init() {
        try {
            isWindow = isWindowsOS();

            // 获得T2Services的实例
            sdkServices = T2Services.getInstance();
            // 加载t2sdk-config.xml配置并初始化连接
            sdkServices.setT2sdkConfigString("classpath:t2sdk-config.xml");
            sdkServices.init();
            sdkServices.start();
        } catch (Exception e) {
            LOG.error(e.toString(), e);
        }
    }

    private boolean isWindowsOS() {
        boolean isWindowsOS = false;
        String osName = System.getProperty("os.name");
        if (osName.toLowerCase().indexOf("windows") > -1) {
            isWindowsOS = true;
        }
        return isWindowsOS;
    }
    private IClient getIClient(String nodeName) throws T2SDKException {
        return sdkServices.getClient(nodeName);
    }
    public <T> T callT2(String functionId, IFSForm param, Class<T> clazz)  {
        Map<String, Object> resultData= callT2Inner(functionId,param,clazz);
        resultData.remove("errors");//返回结果接收对象需要整理，暂时在这里简单处理
        return JresUtil.bodyProtocolToBean(resultData , clazz);
    }
    private <T> Map<String, Object> callT2Inner(String functionId, IFSForm param, Class<T> clazz)  {
        boolean isList = true;
        try {
            clazz.getDeclaredField("data_list");
        } catch (NoSuchFieldException e) {
            isList = false;
        }


        LOG.info("callT2:functionId[" + functionId + "] [api->itn]"+param);
        IEvent event = ContextUtil.getServiceContext().getEventFactory().getEventByAlias(functionId, EventType.ET_REQUEST);

        String nodeName = getParentNameInConfig();
        MapWriter mw = new MapWriter();
        for (Map.Entry<String, Field> entry : ReflectionUtil.listAllFields(param.getClass()).entrySet()) {
            mw.put(entry.getKey(), ReflectionUtil.getValueRough(param , entry.getValue()));
        }
        event.putEventData(mw.getDataset());
        IEvent resultEvt;
        try{
            resultEvt = getIClient(nodeName).sendReceive(event);
            LOG.info("请求包发送成功" + resultEvt);
        }catch (T2SDKException e){
            e.printStackTrace();
            LOG.error("call T2 exception", e);
            return LedUtil.genCommErrorResult();
        }
        // 获得结果集
        IDatasets dss = resultEvt.getEventDatas();

        Map<String, Object> result = new HashMap<String, Object>();
        if (dss != null) {
            int datasetCount = dss.getDatasetCount();
            if (1 > datasetCount) {
                // 没结果失败
                return VOUtil.setBGErrorResult(result, resultEvt.getErrorNo(), resultEvt.getErrorInfo());
            } else {
                if (1 < datasetCount) {
                    LOG.warn("more than one dataset, only take first");
                }
                int rc = dss.getDataset(0).getRowCount();

                if (isList) {
                    List<Map<String, Object>> resultList = new ArrayList<Map<String, Object>>(
                            rc);
                    dss.getDataset(0).beforeFirst();
                    while (dss.getDataset(0).hasNext()) {
                        dss.getDataset(0).next();

                        Map<String, Object> rowResult = new HashMap<String, Object>();
                        int lc = dss.getDataset(0).getColumnCount();
                        String v = "";
                        for (int i = 1; i <= lc; i++) {
                            try {
                                v = new String(dss.getDataset(0).getString(i).getBytes("UTF-8"));
                                rowResult.put(dss.getDataset(0).getColumnName(i),""+v);
                            } catch (Exception e){
                                LOG.error(e.toString(), e);
                            }
                        }
                        resultList.add(rowResult);
                    }
                    result = new HashMap<String, Object>();
                    result.put(LedFields.RESULT_LIST, resultList);
                } else {
                    if(dss.getDataset(0).getColumnName(0)!=null){
                        result = new HashMap<String, Object>();
                        try {
                            String v = new String(dss.getDataset(0).getString(0).getBytes("UTF-8"));
                            result.put(dss.getDataset(0).getColumnName(0), v);
                        } catch (Exception e){
                            LOG.error(e.toString(), e);
                        }
                    }else{
                        int columnCount = dss.getDataset(0).getColumnCount();
                        // 遍历单个结果集列信息
                        for (int j = 1; j <= columnCount; j++) {
                            try {
                                String v = new String(dss.getDataset(0).getString(j).getBytes("UTF-8"));
                                result.put(dss.getDataset(0).getColumnName(j), ""+v);
                            } catch (Exception e) {
                                LOG.error(e.toString(), e);
                                continue;
                            }
                        }
                    }
                }
            }
        }
        LOG.info("callT2:functionId[" + functionId + "] [itn->api]"+result);
        int returnCode = resultEvt.getReturnCode();
        LOG.info("Itn Error Code :"+returnCode);
        if (EventReturnCode.I_OK == returnCode) { // 业务正常
            if (!result.containsKey(LedFields.ERROR_NO)) {
                VOUtil.setBGErrorResult(result, ValueUtil.getString(result.get(LedFields.ERROR_NO)),
                        ValueUtil.getString(result.get(LedFields.ERROR_INFO)));
            }
            return result;
        } else {
            if (!result.containsKey(LedFields.ERROR_NO)) {
                String errorNo = resultEvt.getErrorNo();
                if ("0".equals(errorNo)) {
                    return VOUtil.genErrorResult(ValueUtil.getString(returnCode),
                            "");
                } else {
                    String errorInfo = null;
                    try {
                        errorInfo = new String(resultEvt.getErrorInfo().getBytes("UTF-8"));
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                    }
                    return VOUtil.setBGErrorResult(result, errorNo, errorInfo);
                }
            } else {
                LOG.error("call remote itn t2 server error: error_no is {} and error_info is {}  ", ValueUtil.getString(result
                        .get(LedFields.ERROR_NO)), ValueUtil.getString(result
                        .get(LedFields.ERROR_INFO)));
                return VOUtil.setBGErrorResult(result,ValueUtil.getString(result
                        .get(LedFields.ERROR_NO)), ValueUtil.getString(result
                        .get(LedFields.ERROR_INFO)));
            }
        }

    }

    private static String getParentNameInConfig() {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        try {
            DocumentBuilder builder = factory.newDocumentBuilder();
            URL url = ResourceUtils.getURL("classpath:t2sdk-config.xml");
            Document docu = builder.parse( url.openStream() );
            NodeList nl = docu.getElementsByTagName("parent");
            for(int i = 0 ; i < nl.getLength() ; i++ ) {
                Node node = nl.item(i);
                NamedNodeMap nodeMap = node.getAttributes();
                for(int j = 0 ; j < node.getAttributes().getLength() ; i++) {
                    Node attrNode = nodeMap.item(j);
                    if( attrNode.getNodeName().equals("parentName") ) {
                        return attrNode.getNodeValue();
                    }
                }
            }
        } catch (ParserConfigurationException | IOException | SAXException e) {
            e.printStackTrace();
        }
        return "";
    }
}
